﻿using System;
using System.Collections.Generic;
using System.Threading;
using Director.StockSharp.Transaq.Native;
using Director.StockSharp.Transaq.Native.Responses;

namespace Director
{
	delegate void NewExceptionDataHandler(Exception exception);
    delegate void NewBoolDataHandler(bool data);

	static class TXmlConnector
	{
        private static bool _bConnected; // флаг наличия подключения к серверу
        
        public static AutoResetEvent StatusDisconnected = new AutoResetEvent(true);
        public static int StatusTimeout;

        static NewBoolDataHandler _sendNewStatus;

		private static readonly Dictionary<Type, Action<BaseResponse>> _handlerBunch = new Dictionary<Type, Action<BaseResponse>>();
		private static NewExceptionDataHandler _newExceptionDataHandler;

		public static DataHolder DataHolder { get; private set; }

		static TXmlConnector()
		{
			DataHolder = new DataHolder();
			AddResponseHander<ServerStatusResponse>(OnNewServerStatus);
			AddResponseHander<SecInfoResponse>(DataHolder.OnNewSecInfoResponse);
			AddResponseHander<SecuritiesResponse>(DataHolder.OnNewSecuritiesResponse);
			AddResponseHander<PitsResponse>(DataHolder.OnNewPitsResponse);
			AddResponseHander<ClientResponse>(DataHolder.OnNewClientResponse);
			AddResponseHander<PositionsResponse>(DataHolder.OnNewPositionsResponse);
			AddResponseHander<OvernightResponse>(DataHolder.OnNewOvernightResponse);
			AddResponseHander<MarketsResponse>(DataHolder.OnNewMarketsResponse);
			AddResponseHander<BoardsResponse>(DataHolder.OnNewBoardsResponse);
			AddResponseHander<CandleKindsResponse>(DataHolder.OnNewCandleKindsResponse);

			AddResponseHander<CandlesResponse>(DataHolder.OnNewCandlesResponse);
			AddResponseHander<MessagesResponse>(DataHolder.OnNewMessagesResponse);
			AddResponseHander<QuotationsResponse>(DataHolder.OnNewQuotationsResponse);
			AddResponseHander<TradesResponse>(DataHolder.OnNewTradesResponse);
			AddResponseHander<OrdersResponse>(DataHolder.OnNewOrdersResponse);
		}

		private static void OnNewServerStatus(ServerStatusResponse statusResponse)
		{
			_bConnected = statusResponse.Connected == "true";
			if (!string.IsNullOrEmpty(statusResponse.Text))
			{
				Log.WriteLog(statusResponse.Text);
			}
			NewStatus();
		}

		private static void AddResponseHander<T>(Action<T> act) where T : BaseResponse
		{
			_handlerBunch.Add(typeof(T), t => act((T)t));
		}

		public static void ConnectorSetCallback(NewBoolDataHandler newStatus, NewExceptionDataHandler newExceptionDataHandler)
		{
			_sendNewStatus = newStatus;
			_newExceptionDataHandler = newExceptionDataHandler;

			DllProxy.SetCallback(MyCallBack);
        }

		static void MyCallBack(string data)
		{
			try
			{
				var response = XmlSerializeHelper.Deserialize(data);

				if (!response.IsSuccess)
				{
					SendOutError(response.Exception);
					return;
				}

				Action<BaseResponse> action;
				var type = response.GetType();
				if (_handlerBunch.TryGetValue(type, out action))
				{
					action(response);
				}
				else
				{
					Console.WriteLine(type);
				}
				
			}
			catch (Exception ex)
			{
				SendOutError(ex);
			}
		}

		private static void SendOutError(Exception exception)
		{
			_newExceptionDataHandler.BeginInvoke(exception, null, null);
		}
 
        static void NewStatus()
        {
	        _sendNewStatus.BeginInvoke(_bConnected, null, null);

			if (_bConnected)
            {
                StatusDisconnected.Reset();
            }
            else
            {
                StatusDisconnected.Set();
            }
        }

		public static IDllProxy DllProxy { get; set; }

        public static bool ConnectorInitialize(String path, Int16 logLevel)
        {
	        return DllProxy.Initialize(path, logLevel);
        }

		public static void ConnectorUnInitialize()
        {

            if (StatusDisconnected.WaitOne(StatusTimeout))
            {
	            DllProxy.UnInitialize();
            }
            else
            {
                Log.WriteLog("WARNING! Не дождались статуса disconnected. UnInitialize() не выполнено.");
            }

        }
	}
}
